package scripting.handler;

import configs.ServerConfig;
import database.DatabaseScriptAPI;
import handling.channel.ChannelServer;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import scripting.AbstractScriptManager;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class HandlerScriptManager extends AbstractScriptManager {

    private static Logger log = LogManager.getLogger();
    private static HandlerScriptManager instance;

    private final Map<String, Invocable> handlerEvents = new LinkedHashMap<>();

    public static HandlerScriptManager getInstance() {
        if (instance == null) {
            instance = new HandlerScriptManager();
        }
        return instance;
    }

    private String getFullPath(String filename) {
        return "handler/" + filename + ".js";
    }

    public void init() {
        handlerEvents.forEach((script, iv) -> {
            try {
                iv.invokeFunction("dispose", (Object) null);
            } catch (ScriptException | NoSuchMethodException ignored) {
            }
        });
        handlerEvents.clear();
        String[] scripts = ServerConfig.CHANNEL_HANDLERS.trim().split(",");
        for (String script : scripts) {
            if (!script.isEmpty()) {
                Invocable iv = getHandlerInvocable(getFullPath(script));
                if (iv != null) {
                    handlerEvents.put(script, iv);
                }
            }
        }
        handlerEvents.forEach((script, iv) -> {
            try {
                ((ScriptEngine) iv).put("hm", this);
                ((ScriptEngine) iv).put("channels", ChannelServer.getAllInstances());
                iv.invokeFunction("init", (Object) null);
            } catch (final Exception ex) {
                log.error("装载handler脚本出现错误[" + script + "]", ex);
            }
        });
    }

    public Object handler(String name, Object... args) {
        if (handlerEvents.containsKey(name)) {
            try {
                return handlerEvents.get(name).invokeFunction("handler", args);
            } catch (ScriptException | NoSuchMethodException e) {
                log.error("执行handler脚本出现错误[" + name + "]", e);
            }
        }
        return null;
    }

    /**
     * 数据库 查询数据
     *
     * @param sql  SQL语句
     * @param data SQL语句的内嵌数据，可留空
     * @return
     */
    public List<Map<String, Object>> sql_Select(String sql, Object... data) {
        return DatabaseScriptAPI.SQLSelect(sql, data);
    }

    /**
     * 数据库 插入数据
     *
     * @param sql  SQL语句
     * @param data SQL语句的内嵌数据，可留空
     * @return 受影响的行总数
     */
    public int sql_Insert(String sql, Object... data) {
        return DatabaseScriptAPI.SQLInsert(sql, data);
    }

    /**
     * 数据库 更新数据或删除数据
     *
     * @param sql  SQL语句
     * @param data SQL语句的内嵌数据，可留空
     * @return 受影响的行总数
     */
    public int sql_Update(String sql, Object... data) {
        return DatabaseScriptAPI.SQLUpdate(sql, data);
    }
}
